#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "HoString.h"

char* substr(char *str, int start, int length) {
	char *temp = str;
	int str_len = string_len(str);
	if (start >= str_len || start < 0 || length <= 0 || start + length >= str_len) {
		return (char*)NULL;
	} else {
		temp += start;
	}
	char *result = (char*)malloc(sizeof(char) * length);
	memset(result, 0, sizeof(char) * length);
	for (int i = 0; i < length; ++i) {
		*result = *temp;
		++result;
		++temp;
	}
	result -= length;
	return result;
}

char* substring(char *str, int start, int end) {
	char *temp = str;
	int str_len = string_len(str);
	if (start >= str_len || start < -str_len || end - start < 0) {
		return (char*)NULL;
	} else if (start < 0 && start >= -str_len) {
		temp += (str_len + start);
	} else {
		temp += start;
	}
	char *result = (char*)malloc(sizeof(char) * (end - start));
	memset(result, 0, sizeof(char) * (end - start));
	int i = start;
	for (; i < end; ++i) {
		*result = *temp;
		++result;
		++temp;
	}
	result -= (end - start);
	return result;
}

char* str_replace(char *str, char *search, char *replace) {
	int str_len = string_len(str);
	int search_len = string_len(search);
	int replace_len = string_len(replace);
	if (str_len < search_len) {
		return (char*)NULL;
	}
	int start = 0;
	char *result = create_string("");
	for (; start < str_len; ) {
		char *searched = substr(str, start, search_len);
		if (string_compare(searched, search) == TRUE) {
			result = catenate_string(result, replace);
			if ((str_len - (start + search_len)) < search_len) {
				result = catenate_string(result, substr(str, start + search_len, str_len - (start + search_len)));
				break;
			}
			start += search_len;
		} else {
			char c = str[start];
			char *temp = (char*)malloc(sizeof(char*) * 2);
			memset(temp, 0, sizeof(char*) * 2);
			*temp = c;
			result = catenate_string(result, temp);
			++start;
		}
	}
	return result;
}

BOOL string_compare(char *str1, char *str2) {
	char *temp1 = str1, *temp2 = str2;
	int str1_len = string_len(temp1);
	int str2_len = string_len(temp2);
	if (str1_len != str2_len) {
		return FALSE;
	} else {
		while (*temp1) {
			if (*temp1 != *temp2) {
				return FALSE;
			}
			++temp1;
			++temp2;
		}
		return TRUE;
	}
}

char* create_string(char *str) {
	int len = string_len(str);
	char* s = (char*)malloc(sizeof(char) * (len + 1));
	memset(s, 0, sizeof(char) * (len + 1));
	if (s != NULL) {
		if (len > 0) {
			strcpy(s, str);
		} else {
			strcpy(s, "");
		}
	}
	return s;
}

char* catenate_string(char* str1, char* str2) {
	int str1_len = string_len(str1), str2_len = string_len(str2);
	if (str1_len == 0 && str2_len == 0) {
		return (char*)NULL;
	}
	int len = str1_len + str2_len;
	char* s = (char*)malloc(sizeof(char) * (len + 1));
	memset(s, 0, sizeof(char) * (len + 1));
	if (s != NULL) {
		if (str1_len > 0 && str2_len > 0) {
			strcpy(s, str1);
			strcat(s, str2);
		} else if (str1_len > 0 && str2_len == 0) {
			strcpy(s, str1);
		} else if (str1_len == 0 && str2_len > 0) {
			strcpy(s, str2);
		}
	}
	return s;
}

int string_len(char* str) {
	char* temp = str;
	if (temp == (char*)NULL) {
		return 0;
	}
	int len = 0;
	while (*temp) {
		++len;
		++temp;
	}
	return len;
}

BOOL has_headtail_space(char *str) {
	char *temp = str;
	int temp_len = string_len(temp);
	while (*temp) {
		if (*temp == ' ') {
			return TRUE;
		} else {
			break;
		}
		++temp;
	}
	while (*temp) {
		++temp;
	}
	--temp;
	while (*temp) {
		if (*temp == ' ') {
			return TRUE;
		} else {
			break;
		}
		--temp;
	}
	return FALSE;
}

char* trim_string(char *str) {
	char *temp = str, *temp_c = (char*)malloc(sizeof(char) * 2);
	int temp_len = string_len(temp);
	char *result = (char*)malloc(sizeof(char) * temp_len);
	char c;
	memset(result, 0, sizeof(char) * temp_len);
	memset(temp_c, 0, sizeof(char) * 2);
	BOOL is_left = FALSE, is_right = FALSE;
	while (*temp) {
		c = *temp;
		if (c == ' ' && !is_left) {
			++temp;
			continue;
		}
		*temp_c = c;
		strcat(result, temp_c);
		++temp;
		if (!is_left) {
			is_left = TRUE;
		}
	}
	--temp;
	int right_index = 0;
	while (*temp) {
		c = *temp;
		if (c == ' ') {
			++right_index;
		} else {
			break;
		}
		--temp;
	}
	result = substr(result, 0, string_len(result) - right_index);
	return result;
}

char* get_visible_string(char *str) {
	char *temp = str;
	char *result = (char*)malloc(sizeof(char) * (string_len(temp) + 1));
	char *t = (char*)malloc(sizeof(char) * 2);
	memset(result, 0, sizeof(char) * (string_len(str) + 1));
	memset(t, 0, sizeof(char) * 2);
	strcpy(result, "");
	strcpy(t, "");
	while (*temp) {
		char c = *temp;
		if (c >= (char)33 && c <= (char)126) {
			*t = c;
			strcat(result, t);
		}
		++temp;
	}
	free(t);
	return result;
}

void* destroy_string(char* str) {
	if (str != NULL) {
		free(str);
	}
	return NULL;
}

char** string_sort_bylength(int array_length, char **source) {
	int i = 0, j;
	for (; i < array_length - 1; ++i) {
		for (j = 0; j < array_length - 1 - i; ++j) {
			if (string_len(source[j]) < string_len(source[j + 1])) {
				char *temp = source[j];
				source[j] = source[j + 1];
				source[j + 1] = temp;
			}
		}
	}
	return source;
}

char* get_strings_head(int str_count, char **strs) {
	char *s = (char*)NULL;
	char *temp = (char*)malloc(sizeof(char) * 2);
	memset(temp, 0, sizeof(char) * 2);
	int i = 0;
	for (; i < str_count; ++i) {
		*temp = *(strs[i]);
		s = catenate_string(s, temp);
	}
	return s;
}

char *push_stack(char *stack, char c) {
	char *temp = (char*)malloc(sizeof(char) * 2);
	memset(temp, 0, sizeof(char) * 2);
	*temp = c;
	stack = catenate_string(stack, temp);
	return stack;
}

char pop_stack(char **stack) {
	int len = string_len(*stack);
	if (len <= 0) {
		return 0;
	}
	char c = (*stack)[len - 1];
	*stack = substr(*stack, 0, len - 1);
	return c;
}

BOOL is_letter_start(char *s) {
	if (string_len(s) == 0) {
		return FALSE;
	}
	if ((*s >= 'a' && *s <= 'z') ||
		(*s >= 'A' && *s <= 'Z')) {
		return TRUE;
	} else {
		return FALSE;
	}
}

BOOL is_underline_start(char *s) {
	if (string_len(s) == 0) {
		return FALSE;
	}
	if (*s == '_') {
		return TRUE;
	} else {
		return FALSE;
	}
}

BOOL is_sth_start(char *s, char start) {
	if (string_len(s) == 0) {
		return FALSE;
	}
	if (*s == start) {
		return TRUE;
	} else {
		return FALSE;
	}
}

BOOL in_words_array(char **array, int array_length, char *search) {
	int i = 0;
	for (; i < array_length; ++i) {
		if (string_compare(array[i], search)) {
			return TRUE;
		}
	}
	return FALSE;
}

BOOL in_words_array_ex(char **array, int array_length, char *search, int index, int *len_pointer) {
	int i = 0;
	for (; i < array_length; ++i) {
		int array_index_len = string_len(array[i]);
		if (string_compare(array[i], substr(search, index, array_index_len))) {
			*len_pointer = array_index_len;
			return TRUE;
		}
	}
	return FALSE;
}

BOOL in_string(char *array, char search) {
	char *temp = array;
	while (*temp) {
		if (*temp == search) {
			return TRUE;
		}
		++temp;
	}
	return FALSE;
}
